#include<iostream>
#include<cmath>
#include<random>
#include<stdint.h>
#include<immintrin.h> //simd

void test(){
    std::random_device rd; // 用于获取种子
    std::mt19937_64 gen(rd());
    uint64_t e15=1e15; // 以随机设备 rd 初始化 Mersenne Twister 生成器
    uint64_t e14=1e14;
    uint64_t num=gen()%uint64_t(9e14) + e14;//[1e14,1e15)

    printf("num=%lld\n",num);
    uint64_t e8=1e8;

    uint64_t high7=num/e8;
    uint64_t low8=num%e8;
    __m512i hl = _mm512_set_epi64(high7,high7,high7,high7,low8,low8,low8,low8);
    const __m512i t1 = _mm512_set_epi64(90071993,140737489,109951163,42949673,90071993,140737489,109951163,42949673);
    const __m512i t2 = _mm512_set_epi64(53,47,40,32,53,47,40,32);
    const __m512i t3 = _mm512_set_epi64(1e8,1e6,1e4,1e2,1e8,1e6,1e4,1e2);
    const __m512i t4 = _mm512_set_epi64(140737489,109951163,42949673,134217729,140737489,109951163,42949673,134217729);
    const __m512i t5 = _mm512_set_epi64(47,40,32,27,47,40,32,27);
    __m512i res = ((hl-(hl*t1>>t2)*t3)*t4)>>t5;
    for(int i=0;i<8;++i){
        printf("i:%d\n",res[i]);
    }

    //     const __m512d pow10_n2_n16_d = _mm512_set_pd(1e-2, 1e-4, 1e-6, 1e-8, 1e-10, 1e-12, 1e-14, 1e-16);
	// 	const __m512i pow10_2_16_i = _mm512_set_epi64(1e2, 1e4, 1e6, 1e8, 1e10, 1e12, 1e14, 1e16);
	// 	const __m512d pow10_n0_n14_d = _mm512_set_pd(1e0, 1e-2, 1e-4, 1e-6, 1e-8, 1e-10, 1e-12, 1e-14);
	// 	__m512d num2_rest_d = _mm512_set1_pd((double)num2_rest);
	// 	__m512i num2_rest_i = _mm512_set1_epi64(num2_rest);
	// 	__m512d num2r_mul_p10_d = _mm512_mul_pd(num2_rest_d, pow10_n2_n16_d);
	// 	__m512i num2r_mul_p10_i = _mm512_cvttpd_epi64(num2r_mul_p10_d);
	// 	__m512i num2r_div_p10_i = _mm512_mullo_epi64(num2r_mul_p10_i, pow10_2_16_i);
	// 	__m512i num2r_sub_num2r_div_p10_i = _mm512_sub_epi64(num2_rest_i, num2r_div_p10_i);
	// 	__m512d num2r_sub_num2r_div_p10_d = _mm512_cvtepi64_pd(num2r_sub_num2r_div_p10_i);
	// 	__m512d num2r_result_d = _mm512_mul_pd(num2r_sub_num2r_div_p10_d, pow10_n0_n14_d);
	// 	__m512i result_8 = _mm512_cvttpd_epi64(num2r_result_d);
}
void test_func(){
    unsigned long long num1=10000000000000000ull;
    unsigned long long num2= 193428131138340668;
    const unsigned long long M32 = (1ull<<32)-1;
    unsigned long long a = num1>>32;
    unsigned long long b = num1&M32;
    unsigned long long c = num2>>32;
    unsigned long long d = num2&M32;
    unsigned long long  ac = a*c;
    unsigned long long  ad = a*d;
    unsigned long long  bc = b*c;
    unsigned long long  bd = b*d;
    printf("ac=%lld, bc=%lld, ad=%lld,bd=%lld\n",ac,bc,ad,bd);
    printf("((ad+bc)>>32)=%lld\n", (ad>>32) + (bc>>32) );
    //unsigned long long  hi = ac+((ad+bc)>>32);
    unsigned long long  hi = ac  +  (unsigned long long) (ad>>32) +   (unsigned long long) (bc>>32);
    unsigned long long  lo = bd+(ad&M32)+(bc&M32);
    //unsigned long long  lo = bd+((ad+bc)&M32);
    //hi += lo>>63;
    printf("num1=%llx,num2=%llx\n",num1,num2);
    printf("a=%x,b=%x,c=%x,d=%x\n",a,b,c,d);
    printf("hi=%lld lo=%llx,lo=%lld,res=%lld\n",hi,lo,lo,hi>>20);
    unsigned long long mul_res = 0;
    _mulx_u64(num1,num2,&mul_res);
    printf("mul_res=%lld low=%lld\n",mul_res,num1*num2);
}
int main(){
    test_func();


    std::random_device rd; // 用于获取种子
    std::mt19937_64 gen(rd());
    //double num = 14821387422376473/pow(2,52);
    // double num = pow(2,668) * pow(5,-287);
    // printf("num=%.16le\n",num);

    // uint64_t n = 1e8;
    // uint64_t d = 1e2;
    // int N = 64 - __builtin_clzll(n);
    // int l = 64 - __builtin_clzll(d-1);
    // //printf("__builtin_clzll(n)=%d\n",__builtin_clzll(n));
    // printf("N=%d l=%d\n",N,l);
    // uint64_t low = (1ull << (N+l))/d;
    // uint64_t high = ((1ull << (N+l))+(1ull<<l) )/d;
    // while( (low>>1) < (high>>1) && (l>0)  ){
    //     low>>=1;
    //     high>>=1;
    //     --l;
    // }
    // uint64_t n_high=n*high;
    // printf("n_high=%16llx  h=%x\n",n_high,n_high>>60);
    // printf("low=%llu, high=%llu l=%d N+l=%d\n",low,high,l,N+l);

    // int res=(n*high)>>(N+l);
    // printf("res=%d\n",res);

    //size_t num1=0;
    //size_t num2= 999999999999999;//1e15 - 1
    size_t e15 = 1000000000000000;//1e15
    size_t e12 = 1000000000000;//1e15
    size_t e8 = 1e8;//1e15
    size_t e7 = 1e7;//1e15
    size_t e5 = 1e5;//1e15
    size_t e3 = 1e3;//1e15
    size_t e1 = 1e1;//1e15
    double e_15 = 1e-15;
    size_t e_15_i = *(size_t*)&e_15;
    size_t e_15_i_1 = e_15_i - 1;
    double e_15_1 = *(double*)&e_15_i_1;
        const size_t m8 = 1441151881;
        const size_t m7 = 14411518808;
        const size_t m6 = 144115188076;
        const size_t m5 = 1441151880759;
        const size_t m4 = 14411518807586;
        const size_t m3 = 144115188075859;
        const size_t m2 = 1441151880758559;
        const size_t m1 = 14411518807585589;
    for(size_t i=1;i<=9;i++)
    {
        size_t x1 = i*e8 + 0;
        size_t x2 = i*e8 + (e8-1);
        //printf("i=%d x1/1e15 = %d x2/1e15 = %d\n",i,x1/e15,x2/e15);
        int r = 57;
        
        int num1 = (x1 * m8  ) >> (r);
        int num2 = (x2 * m8  ) >> (r);
        // int num1 = x1 * e_15;
        // int num2 = x2 * e_15;
        printf("i=%d num1=%d num2=%d res=%d\n",i,num1,num2,x1/e8);
    }

    size_t num = 0;
    num = (gen()%100)*1e6 +(gen()%100)*1e4 +(gen()%100)*1e2 +(gen()%100)*1e0;
    size_t mask = (1ull << 57) - 1;
    size_t mask57 = (1ull << 57) - 1;
    size_t num12_345678 = num * m6;
    size_t num34_5678 = ((num12_345678 & mask) * 100);
    size_t num56_78 = ((num34_5678 & mask) * 100);
    size_t num_78 = (num56_78 & mask) * 100;
    int num12 = num12_345678 >> 57;
    int num34 = num34_5678 >> 57;
    int num56 = num56_78 >> 57;
    int num78 = num_78>>57;

    printf("low8=%08d\n",num);
    printf("num12=%d num34=%d num56=%d num78=%d\n",num12,num34,num56,num78);


    num12 = (((num * m8) & mask) *100) >>57;
    num34 = (((num * m6) & mask) *100) >>57;
    num56 = (((num * m4) & mask) *100) >>57;
    num78 = (((num * m2) & mask) *100) >>57;
    printf("num12=%d num34=%d num56=%d num78=%d\n",num12,num34,num56,num78);


    num = (gen()%1000)*1e6 +(gen()%100)*1e4 +(gen()%100)*1e2 +(gen()%100)*1e0;
    //num = 600000000;
    printf("high9=%09d\n",num);
    size_t mask54 = (1ull << 54) - 1;
    // num12 = (((num * 18014398510)&~0)*1) >> 54;
    // num34 = (((num * m6)&mask ) *(100)) >> 57;
    // num56 = (((num * m4)&mask ) *(100)) >> 57;
    // num78 = (((num * m2) &mask) *100) >> 57;

    size_t num123_456789 = (num * 18014398510);
    size_t num45_6789 = (num123_456789&mask54) * 100;
    size_t num67_89 = (num45_6789&mask54) * 100;
    size_t num89_ = (num67_89&mask54) * 100;
    int num123 = num123_456789 >> 54;
    int num45 = num45_6789 >> 54;
    int num67 = num67_89 >> 54;
    int num89 = num89_ >> 54;
    printf("num123=%d num45=%d num67=%d num89=%d\n",num123,num45,num67,num89);

    //m8 = 18014398510;


    num123 = (((num *18014398510)) ) >>54;
    num45 = (((num * m6) & mask57) *100) >>57;
    num67 = (((num * m4) & mask57) *100) >>57;
    num89 = (((num * m2) & mask57) *100) >>57;
    printf("num123=%d num45=%d num67=%d num89=%d\n",num123,num45,num67,num89);

    {
    num = size_t((gen()%1000)*1e6 +(gen()%100)*1e4 +(gen()%100)*1e2 +(gen()%100)*1e0) * size_t(1e8) + size_t((gen()%100)*1e6 +(gen()%100)*1e4 +(gen()%100)*1e2 +(gen()%100)*1e0);
    printf("num=%017lld\n",num);
        size_t high9 = num/int(1e8);
        size_t low8 = num%int(1e8);
        __m512i n8_t = _mm512_set_epi64(high9,high9,high9,high9,low8,low8,low8,low8);
		const size_t m8 = 1441151881;
        const size_t m7 = 14411518808;
        const size_t m6 = 144115188076;
        const size_t m5 = 1441151880759;
        const size_t m4 = 14411518807586;
        const size_t m3 = 144115188075859;
        const size_t m2 = 1441151880758559;
        const size_t m1 = 14411518807585589;
		const __m512i m = _mm512_set_epi64(18014398509,m6,m4,m2,m8,m6,m4,m2);
		const size_t num_temp = (1ull<<57) - 1;
		const __m512i mask8 = _mm512_set_epi64(0xFFFFFFFFFFFFFFFF,num_temp,num_temp,num_temp,num_temp,num_temp,num_temp,num_temp);
		const __m512i t1= _mm512_set_epi64(1,100,100,100,100,100,100,100);
		const __m512i t2= _mm512_set_epi64(54,57,57,57,57,57,57,57);
        __m512i result = _mm512_srlv_epi64(_mm512_mullo_epi64(_mm512_and_epi64(_mm512_mullo_epi64(n8_t,m),mask8),t1),t2);
        for(int i=7;i>=0;--i){
            printf("value[%d]=%d ",i,int(result[i]));
        }
    }
    //test();
}